package com.suishoupai.xmb.service;

import com.suishoupai.xmb.dao.AuthMapper;
import com.suishoupai.xmb.dao.CutAuthMapper;
import com.suishoupai.xmb.dao.CutEmailSecurityMapper;
import com.suishoupai.xmb.dao.CutUserMapper;
import com.suishoupai.xmb.entity.*;
import com.suishoupai.xmb.exception.XmbException;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.List;

/**
 * Created by caojian on 2017/4/1.
 */
@Service
public class AuthService {
    @Autowired
    private CutAuthMapper cutAuthMapper;
    @Autowired
    private AuthMapper authMapper;
    @Autowired
    private EmailService emailService;
    @Autowired
    private CutUserMapper cutUserMapper;
    @Autowired
    private CutEmailSecurityMapper cutEmailSecurityMapper;

    @Value("${xmb.host}")
    private String xmbHost;
    @Value("${auth.active_time}")
    private long activeTime;
    @Value("${email.send-max}")
    private int emailSendMax;


    public void update(Auth auth) {
        auth.setUpdateTime(System.currentTimeMillis());
        if (cutAuthMapper.updateByPrimaryKey(auth) == 0) {
            throw new RuntimeException("更新token失败！");
        }
    }

    public void add(Auth auth) {
        auth.setUpdateTime(System.currentTimeMillis());
        if (authMapper.insertSelective(auth) == 0) {
            throw new RuntimeException("插入失败！");
        }
    }

    public List<Auth> getAll() {
        return cutAuthMapper.getAll();
    }

    /**
     * 验证
     *
     * @param auth
     * @return true通过验证
     */
    public boolean validate(Auth auth) {
        Auth temp = cutAuthMapper.selectByPrimaryKey(auth.getEmail(), auth.getType());
        if (temp == null || !temp.getToken().equals(auth.getToken())) {
            return false;
        }
        if (temp.getUpdateTime() + activeTime < System.currentTimeMillis()) {
            return false;
        }
        return true;
    }

    public boolean hasAuth(String email, int type) {
        return cutAuthMapper.selectByPrimaryKey(email, type) != null;
    }


    /**
     * 添加激活认证
     *
     * @param email
     */
    @Transactional
    public void addActivation(String email) throws XmbException {
        //检查
        User user = cutUserMapper.loadUserByEmail(email);
        if (user != null) {
            throw XmbException.newError("该邮箱账号(" + email + ")已存在。");
        }
        if (this.hasAuth(email, AuthTypeEnum.ACTIVATION.getValue())) {
            throw XmbException.newError("至" + email + "的激活邮件已发送过。");
        }

        Auth auth = new Auth();
        auth.setType(AuthTypeEnum.ACTIVATION.getValue());
        auth.setEmail(email);
        auth.setToken(UUID.randomUUID().toString());
        this.add(auth);
        Map map = new HashMap();
        map.put("url", xmbHost + "/sale/activate?token=" + auth.getToken() + "&email=" + email);
        map.put("xmbHost", xmbHost);
        map.put("activeTime", activeTime / 1000 / 60 / 60);
        if (!emailService.sendMail(email, "账号激活", "activation.html", map)) {
            throw new RuntimeException("邮件发送失败！");
        }
    }

    /**
     * 重新激活
     */
    @Transactional
    public void reActivation(String email) throws XmbException {
        //检查
        User user = cutUserMapper.loadUserByEmail(email);
        if (user != null) {
            throw XmbException.newError("该邮箱账号(" + email + ")已经激活了。");
        }

        int type = AuthTypeEnum.ACTIVATION.getValue();
        Map temp = this.getTokenAndActiveTime(email, type);
        long activeTime = MapUtils.getLong(temp, "activeTime");
        String token = MapUtils.getString(temp, "token");
        Map map = new HashMap();
        map.put("url", xmbHost + "/sale/activate?token=" + token + "&email=" + email);
        map.put("xmbHost", xmbHost);
        map.put("activeTime", activeTime / 1000 / 60 / 60);
        if (!emailService.sendMail(email, "账号激活", "activation.html", map)) {
            throw new RuntimeException("邮件发送失败！");
        }
    }

    /**
     * 重置密码
     *
     * @param email
     */
    @Transactional
    public void addResetPsd(String email) throws XmbException {
        //检查
        User user = cutUserMapper.loadUserByEmail(email);
        if (user == null) {
            throw XmbException.newError("该邮箱账号(" + email + ")不存在。");
        }
        if (!user.getRole().equals(RoleEnum.SALE.getValue())) {//卖家才能重置
            throw XmbException.newError("该邮箱账号(" + email + ")不能重置密码。");
        }
        if (cutEmailSecurityMapper.selectByPrimaryKey(email).getNumber() >= emailSendMax) {
            throw XmbException.newError("该账号(" + email + ")发送邮件已达上限，请明天再试。");
        }

        if (cutEmailSecurityMapper.addNumber(email, emailSendMax) == 0) {
            throw new RuntimeException("不安全！");
        }
        Auth auth = new Auth();
        auth.setType(AuthTypeEnum.RESET_PSD.getValue());
        auth.setEmail(email);
        auth.setToken(UUID.randomUUID().toString());
        this.add(auth);
        Map map = new HashMap();
        map.put("url", xmbHost + "/user/resetPsd?token=" + auth.getToken() + "&email=" + email);
        map.put("xmbHost", xmbHost);
        map.put("activeTime", activeTime / 1000 / 60 / 60);
        if (!emailService.sendMail(email, "重置密码", "resetPsd.html", map)) {
            throw new RuntimeException("邮件发送失败！");
        }
    }

    /**
     * 重发重置密码
     *
     * @param email
     */
    @Transactional
    public void reResetPsd(String email) throws XmbException {
        //检查
        User user = cutUserMapper.loadUserByEmail(email);
        if (user == null) {
            throw XmbException.newError("该邮箱账号(" + email + ")不存在。");
        }
        if (!user.getRole().equals(RoleEnum.SALE.getValue())) {//卖家才能重置
            throw XmbException.newError("该邮箱账号(" + email + ")不能重置密码。");
        }
        if (cutEmailSecurityMapper.selectByPrimaryKey(email).getNumber() >= emailSendMax) {
            throw XmbException.newError("该账号(" + email + ")发送邮件已达上限，请明天再试。");
        }

        if (cutEmailSecurityMapper.addNumber(email, emailSendMax) == 0) {
            throw new RuntimeException("不安全！");
        }
        int type = AuthTypeEnum.RESET_PSD.getValue();
        Map temp = this.getTokenAndActiveTime(email, type);
        long activeTime = MapUtils.getLong(temp, "activeTime");
        String token = MapUtils.getString(temp, "token");
        Map map = new HashMap();
        map.put("url", xmbHost + "/user/resetPsd?token=" + token + "&email=" + email);
        map.put("xmbHost", xmbHost);
        map.put("activeTime", activeTime / 1000 / 60 / 60);
        if (!emailService.sendMail(email, "重置密码", "resetPsd.html", map)) {
            throw new RuntimeException("邮件发送失败！");
        }
    }

    /**
     * 重发时，获取token和有效时间
     *
     * @param email
     * @param type
     * @return
     */
    private Map getTokenAndActiveTime(String email, int type) throws XmbException {
        long activeTime;
        String token;
        Auth temp = cutAuthMapper.selectByPrimaryKey(email, type);
        long currentTime = System.currentTimeMillis();
        long dTime = currentTime - temp.getUpdateTime();
        if (dTime < 60 * 1000) {//小于一分钟
            throw XmbException.newError("请在" + (60 * 1000 - dTime) / 1000 + "秒后重试!");
        }
        if (temp == null || (temp.getUpdateTime() + this.activeTime < currentTime)) {//过期
            token = UUID.randomUUID().toString();
            activeTime = this.activeTime;

            Auth updateAuth = new Auth();
            updateAuth.setEmail(email);
            updateAuth.setType(type);
            updateAuth.setToken(token);
            this.update(updateAuth);
        } else {
            Auth updateAuth = new Auth();
            updateAuth.setEmail(email);
            updateAuth.setType(type);
            this.update(updateAuth);

            token = temp.getToken();
            activeTime = this.activeTime - (currentTime - temp.getUpdateTime());
        }
        Map map = new HashMap();
        map.put("token", token);
        map.put("activeTime", activeTime);
        return map;
    }
}
